/* 
Copyright Paul James Mutton, 2001-2004, http://www.jibble.org/

This file is part of SimpleFTP.

This software is dual-licensed, allowing you to choose between the GNU
General Public License (GPL) and the www.jibble.org Commercial License.
Since the GPL may be too restrictive for use in a proprietary application,
a commercial license is also provided. Full license information can be
found at http://www.jibble.org/licenses/

$Author: pjm2 $
$Id: SimpleFTP.java,v 1.2 2004/05/29 19:27:37 pjm2 Exp $

 */

package simpleftp.client.control;

import java.io.*;
import java.net.*;
import java.util.*;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeModel;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * SimpleFTP is a simple package that implements a Java FTP client. With
 * SimpleFTP, you can connect to an FTP server and upload multiple files.
 * <p>
 * Copyright Paul Mutton, <a
 * href="http://www.jibble.org/">http://www.jibble.org/</a>
 * 
 */
public class SimpleFTP {

	/**
	 * Create an instance of SimpleFTP.
	 */
	public SimpleFTP() {

	}

	/**
	 * Connects to the default port of an FTP server and logs in as
	 * anonymous/anonymous.
	 */
	public void connect(String host) throws IOException {
		connect(host, 21);
	}

	/**
	 * Connects to an FTP server and logs in as anonymous/anonymous.
	 */
	public void connect(String host, int port) throws IOException {
		connect(host, port, "anonymous", "anonymous");
	}

	/**
	 * Connects to an FTP server and logs in with the supplied username and
	 * password.
	 */
	public void connect(String host, int port, String user, String pass)
			throws IOException {
		if (socket != null) {
			throw new IOException(
					"SimpleFTP is already connected. Disconnect first.");
		}

		socket = new Socket(host, port);
		reader = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));
		writer = new BufferedWriter(new OutputStreamWriter(
				socket.getOutputStream()));
		objectReader = new ObjectInputStream(socket.getInputStream());

		String response = readLine();
		if (!response.startsWith("220 ")) {
			throw new IOException(
					"SimpleFTP received an unknown response when connecting to the FTP server: "
							+ response);
		}

		sendLine("USER " + user);

		response = readLine();

		if (!response.startsWith("331 ")) {
			System.out.println("2");
			throw new IOException(
					"SimpleFTP received an unknown response after sending the user: "
							+ response);
		}
		sendLine("PASS " + pass);

		response = readLine();
		if (!response.startsWith("230 ")) {
			throw new IOException(
					"SimpleFTP was unable to log in with the supplied password: "
							+ response);
		}
		// Now logged in.
		fileTree = new File(".");// TODO : ls
		// ls();
	}

	/**
	 * Disconnects from the FTP server.
	 */
	public void disconnect() throws IOException {
		try {
			sendLine("QUIT");
		} finally {
			socket = null;
		}
	}

	/**
	 * Returns the working directory of the FTP server it is connected to.
	 */
	public String pwd() throws IOException {
		sendLine("PWD");
		String dir = null;
		String response = readLine();
		if (response.startsWith("257 ")) {
			System.out.println("PWD " + response);
			int fsLastIndex = response.lastIndexOf(System
					.getProperty("file.separator"));
			if (fsLastIndex > 0)
				dir = response.substring(fsLastIndex + 1);
			else
				dir = response.substring(4);
		}
		return dir;
	}

	/**
	 * Returns a list of files from a directory specified.
	 * 
	 * @throws ClassNotFoundException
	 */
	public String ls() throws IOException {
		sendLine("LIST");

		String listsplit[] = null;
		String list = null;
		String response = readLine();
		if (response.startsWith("200 "))
			listsplit = response.split(" ");
			if(listsplit.length >1)
				list=listsplit[1];
		try {
			//uncomment this line to pass in object mode
			//this.treeModel =(TreeModel)objectReader.readObject();	
			//comment these two lines to pass in object mode
			JSONObject jsoninput = new JSONObject(readLine());
			this.treeModel = json2tree(jsoninput);
		} 
//			catch (ClassNotFoundException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} 
		catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return list;
	}

	/**
	 * Changes the working directory (like cd). Returns true if successful.
	 */
	public boolean cwd(String dir) throws IOException {
		sendLine("CWD " + dir);
		String response = readLine();
		return (response.startsWith("250 "));
	}

	
	private void buildtree(JSONObject json, DefaultMutableTreeNode node)
			throws JSONException {
		JSONArray array = json.names();
		DefaultMutableTreeNode d;
		if(node==null)
		{
			root=new DefaultMutableTreeNode(array.getString(0));
			d=root;
			
		}
		else{
			d=new DefaultMutableTreeNode(array.getString(0));
		node.add(d);
		}
		JSONArray array1 = json.getJSONArray(array.getString(0));
		for (int r = 0; r < array1.length(); r++) {
			Object obj = array1.get(r);
			if(obj instanceof JSONObject)
			{				
				buildtree((JSONObject)obj, d);
			}
			else{
				DefaultMutableTreeNode t=new DefaultMutableTreeNode(obj.toString());
				t.setAllowsChildren(false);
			d.add(t);
			}
			
		}
	}

	private TreeModel json2tree(JSONObject json)
			throws JSONException {
			buildtree(json, null);		
		return new DefaultTreeModel(root,true);
	}

	public boolean stor(File file) throws IOException {
		if (file.isDirectory()) {
			throw new IOException("SimpleFTP cannot upload a directory.");
		}

		String filename = file.getName();

		return stor(new FileInputStream(file), filename);
	}

	public boolean retrv(String filepath, String savepath) throws IOException {

		sendLine("PASV ");
		String response = readLine();
		if (!response.startsWith("227 ")) {
			throw new IOException("SimpleFTP could not request passive mode: "
					+ response);
		}

		String ip = null;
		int port = -1;
		int opening = response.indexOf('(');
		int closing = response.indexOf(')', opening + 1);
		if (closing > 0) {
			String dataLink = response.substring(opening + 1, closing);
			StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
			try {
				ip = tokenizer.nextToken() + "." + tokenizer.nextToken() + "."
						+ tokenizer.nextToken() + "." + tokenizer.nextToken();
				port = Integer.parseInt(tokenizer.nextToken()) * 256
						+ Integer.parseInt(tokenizer.nextToken());
			} catch (Exception e) {
				throw new IOException(
						"SimpleFTP received bad data link information: "
								+ response);
			}
		}

		sendLine("RETR " + filepath);
		Socket dataSocket = new Socket(ip, port);
		response = readLine();
		if (!response.startsWith("150 ")) {
			dataSocket.close();
			throw new IOException(
					"SimpleFTP was not allowed to send the file: " + response);
		}

		try {
			StringTokenizer st = new StringTokenizer(filepath, "\\");
			String filename = "";
			while (st.hasMoreTokens()) {
				filename = st.nextToken();
			}

			OutputStream os = new FileOutputStream(new File(savepath
					+ System.getProperty("file.separator") + filename));
			BufferedInputStream is = new BufferedInputStream(
					dataSocket.getInputStream());
			byte[] buffer = new byte[4096];
			int bytesRead = 0;
			while ((bytesRead = is.read(buffer)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.flush();
			os.close();
			is.close();
			dataSocket.close();
		} catch (IOException e) {
			try {
				sendLine("error");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}

		response = readLine();
		return response.startsWith("226 ");
	}

	/**
	 * Sends a file to be stored on the FTP server. Returns true if the file
	 * transfer was successful. The file is sent in passive mode to avoid NAT or
	 * firewall problems at the client end.
	 */
	public boolean stor(InputStream inputStream, String filename)
			throws IOException {

		BufferedInputStream input = new BufferedInputStream(inputStream);

		sendLine("PASV ");
		String response = readLine();
		if (!response.startsWith("227 ")) {
			throw new IOException("SimpleFTP could not request passive mode: "
					+ response);
		}

		String ip = null;
		int port = -1;
		int opening = response.indexOf('(');
		int closing = response.indexOf(')', opening + 1);
		if (closing > 0) {
			String dataLink = response.substring(opening + 1, closing);
			StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
			try {
				ip = tokenizer.nextToken() + "." + tokenizer.nextToken() + "."
						+ tokenizer.nextToken() + "." + tokenizer.nextToken();
				port = Integer.parseInt(tokenizer.nextToken()) * 256
						+ Integer.parseInt(tokenizer.nextToken());
			} catch (Exception e) {
				throw new IOException(
						"SimpleFTP received bad data link information: "
								+ response);
			}
		}

		sendLine("STOR " + filename);
		Socket dataSocket = new Socket(ip, port);

		response = readLine();
		if (!response.startsWith("150 ")) {
			dataSocket.close();
			throw new IOException(
					"SimpleFTP was not allowed to send the file: " + response);
		}

		BufferedOutputStream output = new BufferedOutputStream(
				dataSocket.getOutputStream());
		byte[] buffer = new byte[4096];
		int bytesRead = 0;
		while ((bytesRead = input.read(buffer)) != -1) {
			output.write(buffer, 0, bytesRead);
		}
		output.flush();
		output.close();
		input.close();
		dataSocket.close();
		response = readLine();
		return response.startsWith("226 ");
	}

	/**
	 * Enter ASCII mode for sending text files. This is usually the default
	 * mode. Make sure you use binary mode if you are sending images or other
	 * binary data, as ASCII mode is likely to corrupt them.
	 */
	public boolean ascii() throws IOException {
		sendLine("TYPE A");
		String response = readLine();
		return (response.startsWith("202 "));
	}

	/**
	 * Sends a raw command to the FTP server.
	 */
	private void sendLine(String line) throws IOException {
		if (socket == null) {
			throw new IOException("SimpleFTP is not connected.");
		}
		try {
			writer.write(line + "\r\n");
			writer.flush();
			if (DEBUG) {
				System.out.println("> " + line);
			}
		} catch (IOException e) {
			socket = null;
			throw e;
		}
	}

	private String readLine() throws IOException {
		String line = reader.readLine();
		if (DEBUG) {
			System.out.println("< " + line);
		}
		return line;
	}

	public File getFileTree() {
		return this.fileTree;
	}

	public TreeModel getTreeModel() {
		return this.treeModel;
	}

	private Socket socket = null;
	private BufferedReader reader = null;
	private BufferedWriter writer = null;
	private ObjectInputStream objectReader = null;
	private File fileTree;
	private TreeModel treeModel;
	private static boolean DEBUG = false;
	private DefaultMutableTreeNode root;
}